package com.bangcommunity.bbframe.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;

public class TryHelper {
    private static Logger logger = LoggerFactory.getLogger(TryHelper.class);
    private static int[] steps = new int[] { 1, 1, 2 };

    public static <T extends Serializable> TryResult<T> tryProcess(int times, Tryable<T> tryable) {
        int c = Math.max(times, 0);
        int time = 0;
        TryResult<T> tryResult = null;
        while (time++ < c) {
            try {
                tryResult = tryable.doTry(time);
            } catch (Exception e) {
                logger.error("dotry exception: ", new Object[] { e });
                continue;
            }
            if (null != tryResult && tryResult.isSuccess()) {
                return tryResult;
            }
            try {
                Thread.sleep(getStepIndex(time) * 1000);
            } catch (InterruptedException e) {
                // swollow
            }
        }
        if (null == tryResult) {
            tryResult = new TryResult<T>();
        }
        tryResult.setSuccess(false);
        return tryResult;
    }

    private static int getStepIndex(int times) {
        times = Math.max(0, times - 1);
        int stepsize = steps.length;
        return times % stepsize;
    }

    public static interface Tryable<T extends Serializable> {
        /**
         *
         * @param time
         *            第几次执行
         */
        public TryResult<T> doTry(int time);
    }

    public static class TryResult<T extends Serializable> implements Serializable {
        private static final long serialVersionUID = 1L;
        protected boolean success = true;
        protected T value;
        protected String errorCode;
        protected String errorMsg;

        public boolean isSuccess() {
            return success;
        }

        public void setSuccess(boolean success) {
            this.success = success;
        }

        public T getValue() {
            return value;
        }

        public void setValue(T value) {
            this.value = value;
        }

        public String getErrorCode() {
            return errorCode;
        }

        public void setErrorCode(String errorCode) {
            this.errorCode = errorCode;
        }

        public String getErrorMsg() {
            return errorMsg;
        }

        public void setErrorMsg(String errorMsg) {
            this.errorMsg = errorMsg;
        }

        @Override
        public String toString() {
            return "TryResult{" + "success=" + success + ", value=" + value + ", errorCode='" + errorCode + '\''
                    + ", errorMsg='" + errorMsg + '\'' + '}';
        }
    }

    public static void main(String[] args) {
        TryHelper.tryProcess(5, new Tryable() {
            @Override
            public TryResult doTry(int time) {
                System.out.println("times======" + time);
                System.out.println("do try");
                TryResult t = new TryResult();
                if (time == 4) {
                    t.setSuccess(true);
                    return t;
                }
                t.setSuccess(false);
                return t;
            }
        });
    }

}
